home *** CD-ROM | disk | FTP | other *** search
/ MacHack 1997 / MacHack 1997.toast / Hacks / Hacks ’93 / Mystery Science Mac / INIT sources / MSM.patches.c < prev    next >
C/C++ Source or Header  |  1993-09-01  |  9KB  |  359 lines

  1. #include "MacHeaders7"
  2. #include "Utils.h"
  3. #include "MSM.h"
  4.  
  5. #include <Balloons.h>
  6. #include <Processes.h>
  7.  
  8. traps Patches[myLast+1] = {
  9.     0xA93D,0,0,                /* MenuSelect */
  10.     0xA96D,0,0,                /* Draw1Control */
  11.     0xA912,0,0,                /* InitWindows */
  12.     0x0000,0,0                /* Last */
  13. };
  14.  
  15. /********************************************************************************/
  16.  
  17. /* it is necessary inside traps to have a convenient way of vectoring back
  18.    to the "old" trap routine.  w/o multi-seg code resources, and if the
  19.    compiler were smart enough, this could be done with PC-relative code,
  20.    something like:
  21.            asm {
  22.                move.l    Patches[myMove].oldAddress,-(a7)
  23.                rts
  24.            }
  25.    Note that this code preserves all registers.  Unfortunately, this code
  26.    does not work in the world of Think C since globals are accessed relative
  27.    to a4.  So instead, we call a routine named vector which performs like
  28.    LoadSeg - it converts the call to vector into a jsr.l or jmp.l to the
  29.    address in question.  This makes future executions of this code faster,
  30.    too.  (For those who are freaks about self-modifying code, it is possible
  31.    to modify vector in such a way that it acts as if there were a JMP or JSR,
  32.    without modifying any code.  This would, however, be much harder to follow
  33.    when debugging through the patch code, and it would be slower, since every
  34.    time through, the address would have to be re-computed.  As luck would
  35.    have it, the non-self-modifying code takes up less space, and while I was
  36.    debugging through it to make sure it worked, it turned up a bug in the
  37.    INIT I was writing where I was accidentally modifying the wrong entry in
  38.    the trap table.  So it's included here for completeness sake and as yet
  39.    another way of making sure an INIT is squeaky clean.
  40.  
  41.    The call to vector should be:
  42.         asm {
  43.             jsr        vector
  44.             dc.w    myMove
  45.         };
  46.     Sometimes you want to do a jsr rather than a jump.  This is simple,
  47.     just invert the selector word:
  48.         asm {
  49.             jsr        vector
  50.             dc.w    ~myMove
  51.         }
  52.    Just to make things complete, we define 2 macros to invoke the vector:
  53. */
  54.  
  55. #define VectorJMP(myTrap) \
  56.         jsr        vector \
  57.         dc.w    myTrap
  58.  
  59. #define VectorJSR(myTrap) \
  60.         jsr        vector \
  61.         dc.w    ~myTrap
  62.  
  63. #define self_modifying_code 1
  64.  
  65. #if self_modifying_code
  66.  
  67. static void vector(short this_parameter_forces_a_link_instruction) {
  68.     asm {
  69.         _SetUpA4
  70.         movem.l    a0/a1/d0/d1,-(a7)    ; don’t disturb the registers!
  71.         move.w    #0x4EF9,d1    ; 4EF9 = JMP.L
  72.         move.l    4(a6),a1    ; a1 is now the return address.
  73.         move.w    (a1),d0        ; d0 is now the trap #.
  74.         bge.s    @JMP
  75.  
  76. JSR:    not.w    d0
  77.         move.w    #0x4EB9,d1    ; 4EB9 = JSR.L
  78.  
  79. JMP:    subq    #4,a1        ; a1 is now the point of original call.
  80.         move.l    a1,4(a6)    ; save it so we return there.
  81.         lea        Patches,a0    ; get the address of Patches array in a0.
  82.         mulu.w    #sizeof(traps),d0    ; d0 is now the offset into Patches for this particular trap.
  83.         move.w    d1,(a1)+    ; d1 = JMP.L or JSR.L
  84.         move.l    OFFSET(traps,oldAddress)(a0,d0),(a1)+
  85.         jsr        FlushCache    ; wipe the cache because we modified our own code.
  86.         movem.l    (a7)+,a0/a1/d0/d1    ; save the registers.
  87.         _RestoreA4
  88.     };    /* and returning takes us back to the jump! */
  89. }
  90.  
  91. #else
  92.  
  93. static void vector(void) {
  94.     asm {
  95.         link    a6,#-4
  96.         move.l    (a6),(a7)    ; so we can easily leave extra space on the stack.
  97.         movem.l    a0/d0,-(a7)    ; don’t disturb the registers!
  98.         move.l    4(a6),a0    ; a1 is now the address of the inline param to vector.
  99.         move.w    (a0)+,d0    ; d0 is now the trap #, and a0 is the real return address.
  100.         move.l    a0,4(a6)    ; save the new return address for the JSR case.
  101.         _SetUpA4
  102.         lea        Patches,a0    ; get the address of Patches array in a0.
  103.         _RestoreA4            ; don’t need a4 anymore.
  104.         tst.w    d0
  105.         bge.s    @JMP        ; negative d0 means we came from the JSR macro.
  106.  
  107. JSR:    not.w    d0            ; d0 is now the un-inverted trap #.
  108.         subq    #4,a6        ; this puts 4 more bytes on the stack and saves the
  109.                             ; return address of the vector call on the stack.  In
  110.                             ; the non-JSR case, the return address gets obliterated.
  111.  
  112. JMP:    mulu.w    #sizeof(traps),d0    ; d0 is now the offset into Patches for this particular trap.
  113.         move.l    OFFSET(traps,oldAddress)(d0,a0),4(a6)
  114.         movem.l    (a7)+,a0/d0
  115.         unlk    a6
  116.     ;    rts            ; this returns to the old trap address, which, either returns to the
  117.                     ; instruction after the VectorJSR macro or in the case of the
  118.                     ; VectorJMP macro, to wherever.
  119.     };
  120. }
  121.  
  122. #endif
  123.  
  124. /********************************************************************************/
  125.  
  126. void FixA4(Handle h) {
  127.     asm {
  128.         move.l    h,a0
  129.         GetHandleSize
  130.         tst.l    d0
  131.         ble.s    @LX
  132.         move.l    (a0),a0
  133.     LP:    subq    #2,d0
  134.         beq        @LX
  135.         cmpi.w    #0x2F0C,(a0)+    ; 2F0C == 'move.l a4,-(a7)'
  136.         bne.s    @LP
  137.         subq    #2,d0
  138.         cmpi.w    #0x49F9,(a0)+    ; 49F9 == 'lea    0x????,a4'
  139.         bne.s    @LP
  140.         cmpi.l    #'rga4',(a0)    ; rga4 is what we want to replace
  141.         bne.s    @LP
  142.         move.l    a4,(a0)
  143.         bra.s    @LP
  144.     LX:
  145.     }
  146. }
  147.  
  148. extern char Launched : 0x910;    /* if non-positive, we’re not running yet. */
  149.  
  150. CGrafPort        *MSMPort;
  151. long            NeedBlack;
  152. static short    countDown = 8;
  153.  
  154. static void MakeTheHoleBlack(void) {
  155.     ProcessSerialNumber    us, front;
  156.     GrafPtr            oldPort;
  157.  
  158.         // let's be really paranoid about when we do this.
  159.         // let's me sure the window manager exists, at least one program
  160.         // has been launched, there's a real menu bar, resources are set
  161.         // to be loaded, we have at least one menu in the menu bar, and
  162.         // there's at least 2K of stack space.
  163.     if (WWExist != 0 || Launched <= 0 || MBarHeight <= 0 || ResLoad == 0 ||
  164.         jbMenuList == 0 || *jbMenuList == 0 || (**jbMenuList).lastMenu == 0 ||
  165.         StackSpace() < 2048) return;
  166.  
  167.         // and make sure the front process is us.
  168.     GetFrontProcess(&us);
  169.     GetCurrentProcess(&front);
  170.     if (us.highLongOfPSN != front.highLongOfPSN) return;
  171.     if (us.lowLongOfPSN  != front.lowLongOfPSN)  return;
  172.  
  173.     if (countDown > 0) {
  174.         countDown--;
  175.         return;
  176.     }
  177.  
  178.     if (TickCount() > NeedBlack) {
  179.         GetPort(&oldPort);
  180.         SetPort(MSMPort);
  181.         FillRgn(gMysterious, "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF");
  182.         NeedBlack = TickCount() + 300;
  183.         SetPort(oldPort);
  184.     }
  185. }
  186.  
  187. static long last_chk;
  188.        long last_non_dialog;
  189.        WindowPeek    lastWP;
  190.  
  191. static short Microsoft, CopyOnce;
  192.  
  193. void pJGNEfilter(short what, EventRecord *ep) {
  194.     EventRecord er;
  195.     WindowPeek    wp;
  196.     Rect        r;
  197.     Point        pt = ep->where, midpt;
  198.     long        now = TickCount();
  199.  
  200.     if (what == 0) {
  201.         er.what = nullEvent;
  202.         ep = &er;
  203.     }
  204.     switch(ep->what) {
  205.         case nullEvent:
  206.             wp = (WindowPeek) FrontWindow();
  207.             if (wp != NULL && wp->windowKind == 2 && GetWVariant(wp) == 1) {
  208.                 CopyOnce = FALSE;
  209.                 if (lastWP != wp) {
  210.                     if (now - last_non_dialog > 600) {
  211.                         r = (**wp->strucRgn).rgnBBox;
  212.                         if (PtInRect(pt, &r)) {
  213.                             QueueSound(7);
  214.                         } else {
  215.                             midpt.h = (r.left + r.right) / 2;
  216.                             midpt.v = (r.top + r.bottom) / 2;
  217.                             if (pt.h - pt.v > midpt.h - midpt.v) {
  218.                                 if (pt.h + pt.v > midpt.h + midpt.v) {
  219.                                     QueueSound(8);
  220.                                 } else {
  221.                                     QueueSound(10);
  222.                                 }
  223.                             } else {
  224.                                 if (pt.h + pt.v > midpt.h + midpt.v) {
  225.                                     QueueSound(11);
  226.                                 } else {
  227.                                     QueueSound(9);
  228.                                 }
  229.                             }
  230.                         }
  231.                         last_non_dialog = now;
  232.                     }
  233.                 } else {
  234.                     last_non_dialog = now;
  235.                 }
  236.             } else {
  237.                 char    title[256];
  238.                 if (wp) GetWTitle(wp, title);
  239.                 if (wp && title[0] == 4 && 'Copy' == *(long*)&title[1]) {
  240.                     if (!CopyOnce) {
  241.                         QueueSound(12);
  242.                         CopyOnce = TRUE;
  243.                     }
  244.                 } else {
  245.                     CopyOnce = FALSE;
  246.                     last_non_dialog = now;
  247.                     if (*(long *)0x911 == 'Micr') {
  248.                         if (!Microsoft) {
  249.                             Microsoft = TRUE;
  250.                             QueueSound(3);
  251.                         }
  252.                     } else {
  253.                         Microsoft = FALSE;
  254.                     }
  255.                 }
  256.             }
  257.         case updateEvt:
  258.             MakeTheHoleBlack();
  259.         break;
  260.         case mouseDown:
  261.             if (PtInRgn(pt, gMysterious)) {
  262.                 QueueSound(6);
  263.             }
  264.         case mouseUp:
  265.         case keyDown:
  266.             last_non_dialog = now;
  267.         break;
  268.     }
  269. }
  270.  
  271. pascal long pMenuSelect(Point pt) {
  272.     long    result;
  273.  
  274.     asm {
  275.         move.l    12(a6),-(a7)
  276.         move.l    pt,-(a7)
  277.         VectorJSR(myMenuSelect)
  278.         move.l    (a7)+,result
  279.         _SetUpA4
  280.         movem.l    a0/a1/d0/d1/d2,-(a7)
  281.     }
  282.  
  283.     if (MenuDisable == 0xBF960003) {
  284.         QueueSound(1);    //    PlayNamedSound("\pNot!", 0);
  285.         HMSetBalloons(FALSE);
  286.     } else if (result == 0x01050001) {
  287.         QueueSound(4);
  288.     } else if (result == 0x01050005) {
  289.         QueueSound(5);
  290.     } else {
  291.     }
  292.  
  293.     asm {
  294.         movem.l    (a7)+,a0/a1/d0/d1/d2
  295.         _RestoreA4
  296.     }
  297.  
  298.     return result;
  299. }
  300.  
  301. pascal void pDraw1Control(ControlHandle ch) {
  302.     uchar    text[256];
  303.     GetCTitle(ch, text);
  304.     asm {
  305.         _SetUpA4
  306.     }
  307.     if (GetCtlValue(ch) == TRUE && jbRelString(text, "\pWarn before emptying") == 0) {
  308.         QueueSound(2);    //    PlayNamedSound("\pWimp!", 0);
  309.     }
  310.     asm {
  311.         _RestoreA4
  312.         unlk    a6
  313.         VectorJMP(myDraw1Control);
  314.     }
  315. }
  316.  
  317. extern long NeedBlack;
  318. RgnHandle gMysterious;
  319. static void PunchOut(void) {
  320.     GrafPtr    oldPort;
  321.     Rect    r, scrn;
  322.     THz        z;
  323.  
  324.     GetPort(&oldPort);
  325.     SetPort(WMgrCPort);
  326.     z = GetZone();
  327.     SetZone(SystemZone());
  328.     if (!gMysterious) {
  329.         gMysterious = NewRgn();
  330.         OpenRgn();
  331.         r.top = 50;
  332.         r.left = 50;
  333.         r.bottom = 150;
  334.         r.right = 150;
  335.         FrameOval(&r);
  336.         CloseRgn(gMysterious);
  337.     }
  338.     r = (**gMysterious).rgnBBox;
  339.     OffsetRgn(gMysterious, WMgrCPort->portRect.right - r.right, WMgrCPort->portRect.bottom - r.bottom);
  340.     PaintRgn(gMysterious);
  341.     DiffRgn(GrayRgn, gMysterious, GrayRgn);
  342.     SetZone(z);
  343.     SetPort(oldPort);
  344.     NeedBlack = TickCount();
  345. }
  346.  
  347. pascal void pInitWindows(void) {
  348.     asm {
  349.         VectorJSR(myInitWindows);
  350.         movem.l    d0/d1/d2/a0/a1/a4,-(a7)
  351.         link    a6,#0
  352.         _SetUpA4
  353.     }
  354.     PunchOut();
  355.     asm {
  356.         unlk    a6
  357.         movem.l    (a7)+,d0/d1/d2/a0/a1/a4
  358.     }
  359. }